home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 19 / Amiga Plus Leser CD 19.iso / Online / anubis-3.6.0 / contrib / msg2smtp.pl next >
Perl Script  |  2002-11-17  |  7KB  |  232 lines

  1. #!/usr/bin/perl
  2.  
  3. # $Id: msg2smtp.pl,v 1.4 2002/10/29 11:34:07 polak Exp $
  4.  
  5. my $usage = qq!
  6. $0 takes a mail message on STDIN and relays it to an SMTP server.
  7.  
  8. $0 -h HOST [options]
  9.   -h HOST        (hostname of SMTP server, often 'localhost')
  10.  
  11.   Options:
  12.  
  13.   -p PORT        (port of the SMTP server)
  14.   -e HELO_DOMAIN (domain we use when to say helo to smtp server)
  15.   -U USERNAME    (ESMTP auth username)
  16.   -P PASSWORD    (ESMTP auth password)
  17.   -m MECHANISM   (ESMTP auth mechanism - default is PLAIN)
  18.   -d             (shows SMTP conversation and perl debugging)
  19.     !;
  20.  
  21. #------------------------------------------
  22. # INDEX
  23.  
  24. # 0. GPL License
  25. # 1. Module Dependencies
  26. # 2. Set options by Command-line Arguments
  27. # 3. Read Message by STDIN
  28. # 4. Extend Net::SMTP to allow us to choose an auth mechanism
  29. # 5. Send message via SMTP
  30.  
  31. #------------------------------------------
  32. # 0. GPL License
  33. #
  34. #  This file is a part of GNU Anubis.
  35. #  Copyright (C) 2001, 2002 The Anubis Team.
  36. #  GNU Anubis is free software; you can redistribute it and/or modify
  37. #  it under the terms of the GNU General Public License as published by
  38. #  the Free Software Foundation; either version 2 of the License, or
  39. #  (at your option) any later version.
  40. #  GNU Anubis is distributed in the hope that it will be useful,
  41. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  42. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  43. #  GNU General Public License for more details.
  44. #  You should have received a copy of the GNU General Public License
  45. #  along with GNU Anubis; if not, write to the Free Software
  46. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  47. #  GNU Anubis is released under the GPL with the additional exemption that
  48. #  compiling, linking, and/or using OpenSSL is allowed.
  49. #  msg2smtp.pl code: Michael de Beer <michael@debeer.org>
  50. #    ext_auth() mainly taken from the Net::SMTP module
  51. #------------------------------------------
  52. # 1. Module Dependencies
  53.  
  54. use warnings;  use strict;
  55. use Getopt::Std;
  56. use vars qw!$opt_h $opt_p $opt_e $opt_U $opt_P $opt_d $opt_m!;
  57.  
  58. # REQUIRED MODULES:
  59. use Mail::Address;
  60. use Net::SMTP;
  61. # perl -MCPAN -e 'install Mail::Address'
  62. # perl -MCPAN -e 'install Net::SMTP'
  63.  
  64. # OPTIONAL MODULES: Authen:SASL (for ESMTP auth)
  65. # perl -MCPAN -e 'install Authen::SASL'
  66.  
  67. # Note: this script originally used functions from Mail::Box to:
  68. # * parse messages and
  69. # * interface with Net::SMTP
  70. # However, I discovered Mail::Box did not support these options:
  71. #   'port username password'
  72. # So, I am not using Mail::Box.
  73. # # use Mail::Box; use Mail::Transport::SMTP;
  74.  
  75. #------------------------------------------
  76. # 2. Set options by Command-line Arguments
  77.  
  78. getopts('dh:p:e:U:P:m:');
  79.  
  80. my (%smtp_options, $host, $username, $password, $auth_mech);
  81.  
  82. if ($opt_h) { 
  83.     $host = $opt_h;
  84. } else {
  85.     print $usage, "\n";
  86.     exit(255);
  87.  
  88. $smtp_options{Port} = $opt_p if ($opt_p);
  89. $smtp_options{Hello} = $opt_e if ($opt_e);
  90. $smtp_options{Debug} = 1 if ($opt_d);
  91. $username = $opt_U if ($opt_U);
  92. $password = $opt_P if ($opt_P);
  93. $auth_mech = $opt_m ? $opt_m : 'PLAIN'; # not tested other AUTH mechanisms
  94.  
  95. #------------------------------------------
  96. # 3. Read Message by STDIN
  97.  
  98. # read the message and parse the headers for RCPT and FROM
  99. my ($from, @rcpt);
  100. my ($txt_head) = '';
  101. my ($txt_body) = '';
  102. # the only trick thing are To: lines that are folded
  103. # I deal with that with 4 Rules, below.
  104.  
  105. my ($tmp, $chunk, @to_addresses);
  106.  
  107. HEAD: while ($tmp = <>){
  108.  
  109. # Rule 1: If it is a folded line, add line to $chunk, skip to next line
  110.   if ($tmp =~ /^\s+\S+/) { $chunk .= $tmp; next HEAD  };
  111.  
  112. # Rule 2: If it is not a folded line, process old chunk
  113.   $_ = $chunk ? $chunk : '';
  114.   if (/^From:/i) { 
  115.       my @from_addresses;
  116.       @from_addresses = Mail::Address->parse($_);
  117.       $from = pop(@from_addresses)->address;
  118.       die "From: address invalid" unless $from;
  119.       die "there is more than one From: address" if @from_addresses;
  120.   } elsif (/^(To|CC|BCC):/i) {
  121.       @to_addresses = (); # re-initialize because we re-enter this loop
  122.       @to_addresses = Mail::Address->parse($_);
  123.       foreach my $obj (@to_addresses) {
  124.       push @rcpt, $obj->address;
  125.       }
  126.   }
  127.   $txt_head .= $chunk if ($chunk);
  128.  
  129. # Rule 3: If the line is a blank line, exit HEAD section
  130.   last HEAD if $tmp =~ /^$/;
  131.  
  132. # Rule 4: start a new chunk
  133.   $chunk = $tmp;
  134. }
  135.  
  136. while (<>){
  137.    $txt_body .= $_;
  138. }
  139.  
  140. #if ($smtp_options{Debug}){print "FROM $from\n"; map {print "TO $_\n"} @rcpt;}
  141.  
  142. #------------------------------------------
  143. # 4. Extend Net::SMTP to allow us to choose and auth mechanism
  144.  
  145. # We make an extend-auth method, as Net::SMTP::auth() 
  146. # does not seem to accurately pick a mechanism
  147.  
  148. package Net::SMTP;
  149. sub ext_auth { # taken from Net::SMTP, only modify $mechanisms
  150.     my ($self, $username, $password, $mechanisms) = @_;
  151.  
  152.     require MIME::Base64;
  153.     require Authen::SASL;
  154.  
  155.     my $m = $self->supports('AUTH',500,["Command unknown: 'AUTH'"]);
  156.     return unless defined $m;
  157.     my $sasl;
  158.  
  159.     if (ref($username) and UNIVERSAL::isa($username,'Authen::SASL')) {
  160.       $sasl = $username;
  161.       $sasl->mechanism($mechanisms);
  162.     }
  163.     else {
  164.       die "auth(username, password)" if not length $username;
  165.       $sasl = Authen::SASL->new(mechanism=> $mechanisms,
  166.                 callback => { user => $username,
  167.                                               pass => $password,
  168.                           authname => $username,
  169.                                             });
  170.     }
  171.     my $client = $sasl->client_new('smtp',${*$self}{'net_smtp_host'},0);
  172.     my $str    = $client->client_start;
  173.  
  174.     # We dont support sasl mechanisms that encrypt the socket traffic.
  175.     # todo that we would really need to change the ISA hierarchy
  176.     # so we dont inherit from IO::Socket, but instead hold it in an attribute
  177.  
  178.     my @cmd = ("AUTH", $client->mechanism, MIME::Base64::encode_base64($str,''));
  179.     my $code;
  180.  
  181.     while (($code = $self->command(@cmd)->response()) == CMD_MORE) {
  182.       @cmd = (MIME::Base64::encode_base64(
  183.     $client->client_step(
  184.       MIME::Base64::decode_base64(
  185.         ($self->message)[0]
  186.       )
  187.     ), ''
  188.       ));
  189.     }
  190.  
  191.     $code == CMD_OK;
  192. }
  193.  
  194. #------------------------------------------
  195. # 5. Send message via SMTP
  196.  
  197. package main;
  198.  
  199. my $smtp = Net::SMTP->new($host, %smtp_options);
  200. $smtp or die "failed to connect to SMTP server";
  201.  
  202. if ($username) { 
  203.   print "WARNING: failed ESMTP auth using username '$username'...trying to send anyway\n" unless $smtp->ext_auth ($username, $password, $auth_mech);
  204. };
  205. $smtp->mail($from) or die "server rejected FROM address '$from'";
  206. $smtp->to(@rcpt, {SkipBad => 1}) or die "server rejected all TO addresses";
  207. $smtp->data() or die "server crashed while preparing to send DATA";
  208. $smtp->datasend($txt_head) or die "server crashed while sending DATA.1";
  209. $smtp->datasend("\n") or die "server crashed while sending DATA.2";
  210. $smtp->datasend($txt_body) or die "server crashed while sending DATA.3";
  211. $smtp->dataend() or die "server crashed while ending DATA";
  212. $smtp->quit or die "server crashed while quiting - message may not be lost";;
  213.  
  214. __END__
  215.  
  216. # $Log: msg2smtp.pl,v $
  217. # Revision 1.4  2002/10/29 11:34:07  polak
  218. # updated to GNU. Now it's GNU Anubis!
  219. #
  220. # Revision 1.3  2002/10/06 11:37:05  madebeer
  221. # added -m MECHANISM option for ESTMP auth
  222. #
  223. # Revision 1.2  2002/10/06 11:33:13  madebeer
  224. # added logging
  225. #
  226.